#ifndef MD5_4_H
#define MD5_4_H

#include <iostream>
#include <string>
#include <cstring>
// 引入SSE指令集头文件
#include <emmintrin.h>  // SSE2
#include <smmintrin.h>  // SSE4.1

using namespace std;

// 定义了Byte，便于使用
typedef unsigned char Byte;
// 定义了32比特
typedef unsigned int bit32;

// MD5的一系列参数。参数是固定的
#define s11 7
#define s12 12
#define s13 17
#define s14 22
#define s21 5
#define s22 9
#define s23 14
#define s24 20
#define s31 4
#define s32 11
#define s33 16
#define s34 23
#define s41 6
#define s42 10
#define s43 15
#define s44 21

/**
 * 使用SSE指令集实现的MD5基本函数
 * 
 * @param x, y, z: __m128i类型，表示4个32位整数
 * @return __m128i类型，表示4个32位整数的结果
 */
#define SSE_F(x, y, z) _mm_or_si128(_mm_and_si128(x, y), _mm_and_si128(_mm_andnot_si128(x, _mm_set1_epi32(-1)), z))
#define SSE_G(x, y, z) _mm_or_si128(_mm_and_si128(x, z), _mm_and_si128(y, _mm_andnot_si128(z, _mm_set1_epi32(-1))))
#define SSE_H(x, y, z) _mm_xor_si128(_mm_xor_si128(x, y), z)
#define SSE_I(x, y, z) _mm_xor_si128(y, _mm_or_si128(x, _mm_andnot_si128(z, _mm_set1_epi32(-1))))

/**
 * 循环左移
 * 
 * @param num: 要左移的数
 * @param n: 左移位数
 * @return 左移后的结果
 */
#define SSE_ROTATELEFT(num, n) _mm_or_si128(_mm_slli_epi32(num, n), _mm_srli_epi32(num, 32 - n))

/**
 * MD5的四个基本操作
 */
#define SSE_FF(a, b, c, d, x, s, ac){ \
  a = _mm_add_epi32(a, _mm_add_epi32(SSE_F(b, c, d), _mm_add_epi32(x, _mm_set1_epi32(ac)))); \
  a = _mm_add_epi32(SSE_ROTATELEFT(a, s), b); \
}

#define SSE_GG(a, b, c, d, x, s, ac){ \
  a = _mm_add_epi32(a, _mm_add_epi32(SSE_G(b, c, d), _mm_add_epi32(x, _mm_set1_epi32(ac)))); \
  a = _mm_add_epi32(SSE_ROTATELEFT(a, s), b); \
}

#define SSE_HH(a, b, c, d, x, s, ac){ \
  a = _mm_add_epi32(a, _mm_add_epi32(SSE_H(b, c, d), _mm_add_epi32(x, _mm_set1_epi32(ac)))); \
  a = _mm_add_epi32(SSE_ROTATELEFT(a, s), b); \
}

#define SSE_II(a, b, c, d, x, s, ac){ \
  a = _mm_add_epi32(a, _mm_add_epi32(SSE_I(b, c, d), _mm_add_epi32(x, _mm_set1_epi32(ac)))); \
  a = _mm_add_epi32(SSE_ROTATELEFT(a, s), b); \
}

// 处理单个字符串的函数声明
Byte *StringProcess_SSE(string input, int *n_byte);

// 使用SSE指令集的四路并行MD5哈希函数声明
void SSE_MD5Hash_4_SSE(string input[4], bit32 state[4][4]);

// 使用SSE指令集的八路并行MD5哈希函数声明（实际是调用两次四路并行）
void SSE_MD5Hash_8_SSE(string input[8], bit32 state[8][4]);

#endif // MD5_4_H
